package com.heima.comment.service.impl;

import com.heima.comment.enums.TempEnum;
import com.heima.comment.pojos.Comment;
import com.heima.comment.service.CommentService;
import com.heima.comment.utils.CommentThreadLocalUtil;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.model.comment.dtos.CommentDto;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.common.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;



@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public ResponseResult saveComment(CommentDto commentDto) {
        ApUser apUser = CommentThreadLocalUtil.getUser();
        if(commentValidate(commentDto,apUser) != AppHttpCodeEnum.SUCCESS){
            return ResponseResult.setAppHttpCodeEnum(commentValidate(commentDto,apUser));
        }
        Comment comment = createNewComment(apUser);
        comment.setForArticle(true);
        comment.setArticleId(commentDto.getArticleId());
        comment.setContent(commentDto.getContent());
        mongoTemplate.save(comment);
        log.info("存储评论成功");
        return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.CREATED);
    }

    @Override
    public PageResponseResult loadCommentList(CommentDto commentDto) {
        if (verifyRefresh()) return null;
        Query query = Query.query(Criteria.where("articleId").is(commentDto.getArticleId()))
                .with(Sort.by(Sort.Direction.DESC,"createdTime"));  // todo minDate有误,暂时排除
        List<Comment> commentList = mongoTemplate.find(query, Comment.class);
        log.info("{}",commentList);
        measureLikes(commentList);
        return pageUpComment(commentDto, commentList);
    }


    @Override
    public ResponseResult setLike(CommentDto commentDto) {
        if(commentDto.getCommentId() == null || commentDto.getOperation() == null){
            return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.FORBIDDEN);
        }
        return setLikeById(commentDto.getOperation(),commentDto.getCommentId() + "");
    }

    @Override
    public ResponseResult saveReplyComment(CommentDto commentDto) {
        ApUser apUser = CommentThreadLocalUtil.getUser();
        if(commentValidate(commentDto,apUser) != AppHttpCodeEnum.SUCCESS){
            return ResponseResult.setAppHttpCodeEnum(commentValidate(commentDto,apUser));
        }
        Comment comment = createNewComment(apUser);
        comment.setReplyToComment(true);
        comment.setReplyToCommentId(commentDto.getCommentId() + "");
        comment.setContent(commentDto.getContent());
        mongoTemplate.save(comment);
        Update update = new Update();
        update.set("updateTime",System.currentTimeMillis())
                .inc("replies");
        mongoTemplate.updateFirst(Query.query(Criteria.where("Id").is(commentDto.getCommentId()))
                , update, Comment.class);
        return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.CREATED);
    }

    @Override
    public PageResponseResult loadReplyCommentList(CommentDto commentDto){
        // todo if (verifyRefreshReply()) return null;
        log.info("{},{}",System.currentTimeMillis(),commentDto.getMinDate());
        Query query = Query.query(Criteria.where("replyToCommentId").is(commentDto.getCommentId()))
                .with(Sort.by(Sort.Direction.DESC,"createdTime"));  // todo minDate有误,暂时排除
        List<Comment> commentList = mongoTemplate.find(query, Comment.class);
        log.info("{},{}",commentDto.getCommentId(),commentList.toString());
        measureLikes(commentList);
        return pageUpComment(commentDto, commentList);
    }

    @Override
    public ResponseResult setReplyLike(CommentDto commentDto){
        if(commentDto.getCommentRepayId() == null || commentDto.getOperation() == null){
            return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.FORBIDDEN);
        }
        return setLikeById(commentDto.getOperation(),commentDto.getCommentRepayId());
    }

    private AppHttpCodeEnum commentValidate(CommentDto commentDto, ApUser apUser){
        // 验证登录需要调用其他微服务,暂时放弃
        // 验证评论,未进行自定义敏感词验证
        if (commentDto.getContent().isEmpty()) {
            log.info("评论内容为空");
            return AppHttpCodeEnum.FORBIDDEN;
        } else if (commentDto.getContent().length() > 140) {
            log.info("评论内容过长");
            return AppHttpCodeEnum.FORBIDDEN;
        } else if (!scanComment(commentDto.getContent())) {
            log.info("评论内容未过审");
            return AppHttpCodeEnum.SUCCESS; //todo 检测暂时不可用,输入什么都返回antispam
        }
        return AppHttpCodeEnum.SUCCESS;
    }

    private boolean scanComment(String content) {
        try {
            Map result = greenTextScan.greeTextScan(content);
            if ("block".equals(result.get("suggestion") + "")) {
                return false;
            } else if ("review".equals(result.get("suggestion") + "")) {
                return false;
            }
        } catch (Exception e) {
            log.error("文本扫描失败", e);
            return false;
        }
        return true;
    }

    private Comment createNewComment(ApUser apUser) {
        Comment comment = new Comment();
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(TempEnum.WORKER_ID.getCode(), TempEnum.DATACENTER_ID.getCode());
        comment.setId(snowflakeIdWorker.nextId() + "");
        comment.setCommentatorId(apUser.getId() + "");
        comment.setCreatedTime(System.currentTimeMillis());
        return comment;
    }

    private ResponseResult setLikeById(Short operation,String Id) {
        if (operation == 0){
            Update update = new Update();
            Query query = new Query().addCriteria(Criteria.where("Id").is(Id));
            List<String> operatedUserIds = new ArrayList<>();
            Comment templateOne = mongoTemplate.findOne(query, Comment.class);
            if (templateOne.getOperatedUserIds() != null){
                operatedUserIds = Arrays.asList(templateOne.getOperatedUserIds());
            }
            operatedUserIds.add(CommentThreadLocalUtil.getUser().getId().toString());
            update.set("operatedUserIds", operatedUserIds);
            update.set("updateTime", System.currentTimeMillis());
            update.inc("likes");
            mongoTemplate.updateFirst(query,update,Comment.class);
            return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS);
        } else if (operation == 1) {
            Update update = new Update();
            Query query = new Query().addCriteria(Criteria.where("Id").is(Id));
            Comment templateOne = mongoTemplate.findOne(query, Comment.class);
            ArrayList<String> operatedUserIds = new ArrayList<>(Arrays.asList(templateOne.getOperatedUserIds()));
            operatedUserIds.remove(CommentThreadLocalUtil.getUser().getId().toString());
            update.set("operatedUserIds", operatedUserIds)
                    .set("updateTime",System.currentTimeMillis())
                    .inc("likes",-1);
            mongoTemplate.updateFirst(query,update,Comment.class);
            return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS);
        }else {
            return ResponseResult.setAppHttpCodeEnum(AppHttpCodeEnum.FORBIDDEN);
        }
    }

    private static PageResponseResult pageUpComment(CommentDto commentDto, List<Comment> commentList) {
        if (commentDto.getIndex() == null){
            commentDto.setIndex(1);
        }   //todo 前端没有传入index
        PageResponseResult pageResponseResult = new PageResponseResult(commentDto.getIndex(), TempEnum.PAGESIZE.getCode(), commentList.size());
        pageResponseResult.setData(commentList);
        pageResponseResult.setCode(AppHttpCodeEnum.SUCCESS.getCode());
        return pageResponseResult;
    }

    private static void measureLikes(List<Comment> commentList) {
        if (commentList.isEmpty()){
            return;
        }
        for(Comment comment: commentList){
            if (comment.getOperatedUserIds() == null){
                return;
            }
            for (String operatedUserId:comment.getOperatedUserIds()){
                if ((CommentThreadLocalUtil.getUser().getId() + "").equals(operatedUserId)){
                    comment.setOperation((short)0);
                }
            }
        }
    }

    private boolean verifyRefresh() {
        Boolean flag = "comment".equals(redisTemplate.opsForValue().get(CommentThreadLocalUtil.getUser().getId()));
        if (flag){
            return true;
        }
        redisTemplate.opsForValue().set(CommentThreadLocalUtil.getUser().getId(),"comment",TempEnum.REFRESHTIME.getCode(), TimeUnit.SECONDS);
        return false;
    }

    private boolean verifyRefreshReply() {
        Boolean flag = "reply".equals(redisTemplate.opsForValue().get(CommentThreadLocalUtil.getUser().getId()));
        if (flag){
            return true;
        }
        redisTemplate.opsForValue().set(CommentThreadLocalUtil.getUser().getId(),"reply",TempEnum.REFRESHTIME.getCode(), TimeUnit.SECONDS);
        return false;
    }

}
